#!/usr/bin/python3
"""
Sets active TuneD profile.

The stage calls sets active TuneD profile to 'profiles' as if one called
'tuned-adm profile <profile>'. In the most usual case, only one active profile
is set. However in case multiple profiles are provided, then TuneD tries to
merge all profiles into active configuration. In case of conflicting values,
the value from the latest profile is used.
"""


import os
import sys

import osbuild.api


SCHEMA = """
"additionalProperties": false,
"required": ["profiles"],
"description": "Manually set TuneD profile.",
"properties": {
  "profiles": {
    "type": "array",
    "description": "TuneD profile to activate. If multiple profiles are provided, TuneD will try to merge them.",
    "minItems": 1,
    "items": {
      "type": "string"
    }
  }
}
"""


class TunedProfilesDB:
    """
    Class for loading available TuneD profiles from the given filesystem tree
    and checking if a profile with particular name exists.
    """
    def __init__(self, tree):
        self._available_profiles = self._load_available_profiles(tree)

    @staticmethod
    def _load_available_profiles(tree):
        """
        Loads available TuneD profiles.

        TuneD determines available profile names by listing all directories
        in 'profile_directories' with "tuned.conf" file inside them. Profile names
        are names of the directories.
        """
        available_profiles = set()

        # Directories, from which TuneD loads profile definitions
        profile_directories = [
            "/usr/lib/tuned",
            "/etc/tuned"
        ]
        profile_config_file = "tuned.conf"

        for path in profile_directories:
            for dir_entry in os.scandir(f"{tree}{path}"):
                if dir_entry.is_dir() and os.path.isfile(f"{tree}{path}/{dir_entry.name}/{profile_config_file}"):
                    available_profiles.add(dir_entry.name)

        return available_profiles

    def check_profile_exists(self, profile):
        """
        Checks whether a profile with the given name exists.
        """
        if profile in self._available_profiles:
            return True
        return False


def main(tree, options):
    # File which holds the name of the active profile
    active_profile_file = "/etc/tuned/active_profile"
    # File which tells TuneD whether the active profile was set manually or automatically
    profile_mode_file = "/etc/tuned/profile_mode"

    profiles = options["profiles"]
    profiles_db = TunedProfilesDB(tree)

    for profile in profiles:
        if not profiles_db.check_profile_exists(profile):
            raise ValueError(f"TuneD profile '{profile}' does not exist")

    # Set the active profile
    with open(f"{tree}{active_profile_file}", "w") as f:
        f.write(" ".join(profiles) + "\n")

    # Mode needs to be set to "manual" if set explicitly
    with open(f"{tree}{profile_mode_file}", "w") as f:
        f.write("manual\n")

    return 0


if __name__ == '__main__':
    args = osbuild.api.arguments()
    r = main(args["tree"], args["options"])
    sys.exit(r)
